package com.xiaozhi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaozhi.entity.Notification;
import com.xiaozhi.mapper.NotificationMapper;
import com.xiaozhi.service.NotificationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 通知服务实现类
 * 实现通知系统的核心业务逻辑
 */
@Service
public class NotificationServiceImpl extends ServiceImpl<NotificationMapper, Notification> implements NotificationService {

    private static final Logger log = LoggerFactory.getLogger(NotificationServiceImpl.class);

    @Autowired
    private NotificationMapper notificationMapper;

    @Override
    @Transactional
    public Notification createNotification(Notification notification) {
        try {
            // 设置默认值
            if (notification.getStatus() == null) {
                notification.setStatus("PENDING");
            }
            if (notification.getPriority() == null) {
                notification.setPriority("NORMAL");
            }
            if (notification.getChannel() == null) {
                notification.setChannel("WEB");
            }
            if (notification.getIsRead() == null) {
                notification.setIsRead(false);
            }
            if (notification.getRetryCount() == null) {
                notification.setRetryCount(0);
            }
            if (notification.getMaxRetries() == null) {
                notification.setMaxRetries(3);
            }
            
            save(notification);
            log.info("创建通知成功: {}", notification.getId());
            return notification;
        } catch (Exception e) {
            log.error("创建通知失败", e);
            throw new RuntimeException("创建通知失败: " + e.getMessage());
        }
    }

    @Override
    public Notification createSystemNotification(Long userId, String title, String content, String priority) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("SYSTEM")
                .setTitle(title)
                .setContent(content)
                .setPriority(priority)
                .setChannel("WEB");
        return createNotification(notification);
    }

    @Override
    public Notification createAppointmentNotification(Long userId, Long appointmentId, String title, String content, LocalDateTime scheduledAt) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("APPOINTMENT")
                .setTitle(title)
                .setContent(content)
                .setPriority("HIGH")
                .setChannel("WEB")
                .setRelatedType("appointment")
                .setRelatedId(appointmentId)
                .setScheduledAt(scheduledAt)
                .setActionUrl("/appointment/" + appointmentId);
        return createNotification(notification);
    }

    @Override
    public Notification createHealthReminderNotification(Long userId, Long healthRecordId, String title, String content, String priority) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("HEALTH")
                .setTitle(title)
                .setContent(content)
                .setPriority(priority)
                .setChannel("WEB")
                .setRelatedType("health_record")
                .setRelatedId(healthRecordId)
                .setActionUrl("/health/" + healthRecordId);
        return createNotification(notification);
    }

    @Override
    public Notification createAnalysisNotification(Long userId, Long analysisId, String title, String content) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("ANALYSIS")
                .setTitle(title)
                .setContent(content)
                .setPriority("NORMAL")
                .setChannel("WEB")
                .setRelatedType("health_analytics")
                .setRelatedId(analysisId)
                .setActionUrl("/analytics/" + analysisId);
        return createNotification(notification);
    }

    @Override
    public Notification createSymptomAssessmentNotification(Long userId, Long assessmentId, String title, String content, String priority) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("SYMPTOM")
                .setTitle(title)
                .setContent(content)
                .setPriority(priority)
                .setChannel("WEB")
                .setRelatedType("symptom_assessment")
                .setRelatedId(assessmentId)
                .setActionUrl("/symptom/" + assessmentId);
        return createNotification(notification);
    }

    @Override
    @Transactional
    public Integer batchCreateNotifications(List<Notification> notifications) {
        try {
            for (Notification notification : notifications) {
                createNotification(notification);
            }
            log.info("批量创建通知成功，数量: {}", notifications.size());
            return notifications.size();
        } catch (Exception e) {
            log.error("批量创建通知失败", e);
            throw new RuntimeException("批量创建通知失败: " + e.getMessage());
        }
    }

    @Override
    public IPage<Notification> getUserNotifications(Page<Notification> page, Long userId, String type, String status, String priority, Boolean isRead) {
        return notificationMapper.selectUserNotifications(page, userId, type, status, priority, isRead);
    }

    @Override
    public List<Notification> getRecentNotifications(Long userId, Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        return notificationMapper.selectRecentNotifications(userId, limit);
    }

    @Override
    public Integer getUnreadNotificationCount(Long userId) {
        return notificationMapper.countUnreadNotifications(userId);
    }

    @Override
    public Map<String, Integer> getUnreadNotificationCountByType(Long userId) {
        List<Map<String, Object>> results = notificationMapper.countUnreadNotificationsByType(userId);
        return results.stream().collect(Collectors.toMap(
                result -> (String) result.get("type"),
                result -> ((Number) result.get("count")).intValue()
        ));
    }

    @Override
    public List<Notification> getHighPriorityUnreadNotifications(Long userId) {
        return notificationMapper.selectHighPriorityUnreadNotifications(userId);
    }

    @Override
    @Transactional
    public Boolean markAsRead(Long userId, Long notificationId) {
        try {
            Notification notification = getById(notificationId);
            if (notification == null || !notification.getUserId().equals(userId)) {
                return false;
            }
            
            notification.setIsRead(true);
            notification.setReadAt(LocalDateTime.now());
            updateById(notification);
            
            log.info("标记通知为已读: {}", notificationId);
            return true;
        } catch (Exception e) {
            log.error("标记通知为已读失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public Integer batchMarkAsRead(Long userId, List<Long> notificationIds) {
        try {
            Integer count = notificationMapper.batchMarkAsRead(userId, notificationIds);
            log.info("批量标记通知为已读，用户: {}, 数量: {}", userId, count);
            return count;
        } catch (Exception e) {
            log.error("批量标记通知为已读失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public Integer markAllAsRead(Long userId, String type) {
        try {
            Integer count = notificationMapper.markAllAsRead(userId, type);
            log.info("标记所有通知为已读，用户: {}, 类型: {}, 数量: {}", userId, type, count);
            return count;
        } catch (Exception e) {
            log.error("标记所有通知为已读失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public Boolean deleteNotification(Long userId, Long notificationId) {
        try {
            Notification notification = getById(notificationId);
            if (notification == null || !notification.getUserId().equals(userId)) {
                return false;
            }
            
            removeById(notificationId);
            log.info("删除通知: {}", notificationId);
            return true;
        } catch (Exception e) {
            log.error("删除通知失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public Integer batchDeleteNotifications(Long userId, List<Long> notificationIds) {
        try {
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                    .in("id", notificationIds);
            
            int count = (int) count(queryWrapper);  // 添加强制类型转换
            remove(queryWrapper);
            
            log.info("批量删除通知，用户: {}, 数量: {}", userId, count);
            return count;
        } catch (Exception e) {
            log.error("批量删除通知失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public Boolean sendNotification(Long notificationId) {
        try {
            Notification notification = getById(notificationId);
            if (notification == null) {
                return false;
            }
            
            // 模拟发送通知的逻辑
            boolean success = simulateSendNotification(notification);
            
            if (success) {
                notificationMapper.updateNotificationStatus(notificationId, "SENT", null);
                log.info("发送通知成功: {}", notificationId);
            } else {
                notificationMapper.updateNotificationStatus(notificationId, "FAILED", "发送失败");
                notificationMapper.incrementRetryCount(notificationId);
                log.warn("发送通知失败: {}", notificationId);
            }
            
            return success;
        } catch (Exception e) {
            log.error("发送通知异常", e);
            notificationMapper.updateNotificationStatus(notificationId, "FAILED", e.getMessage());
            notificationMapper.incrementRetryCount(notificationId);
            return false;
        }
    }

    @Override
    @Transactional
    public Integer processPendingNotifications(Integer limit) {
        try {
            if (limit == null || limit <= 0) {
                limit = 100;
            }
            
            List<Notification> pendingNotifications = notificationMapper.selectPendingNotifications(limit);
            int successCount = 0;
            
            for (Notification notification : pendingNotifications) {
                if (sendNotification(notification.getId())) {
                    successCount++;
                }
            }
            
            log.info("处理待发送通知，总数: {}, 成功: {}", pendingNotifications.size(), successCount);
            return successCount;
        } catch (Exception e) {
            log.error("处理待发送通知失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public Integer retryFailedNotifications(Integer limit) {
        try {
            if (limit == null || limit <= 0) {
                limit = 50;
            }
            
            List<Notification> retryableNotifications = notificationMapper.selectRetryableNotifications(limit);
            int successCount = 0;
            
            for (Notification notification : retryableNotifications) {
                if (sendNotification(notification.getId())) {
                    successCount++;
                }
            }
            
            log.info("重试失败通知，总数: {}, 成功: {}", retryableNotifications.size(), successCount);
            return successCount;
        } catch (Exception e) {
            log.error("重试失败通知异常", e);
            return 0;
        }
    }

    @Override
    public Notification getNotificationDetail(Long userId, Long notificationId) {
        Notification notification = getById(notificationId);
        if (notification != null && notification.getUserId().equals(userId)) {
            return notification;
        }
        return null;
    }

    @Override
    public Map<String, Object> getNotificationStatistics(Long userId, LocalDateTime startTime, LocalDateTime endTime) {
        List<Map<String, Object>> statistics = notificationMapper.getNotificationStatistics(userId, startTime, endTime);
        
        Map<String, Object> result = new HashMap<>();
        result.put("statistics", statistics);
        result.put("total_count", statistics.stream().mapToInt(stat -> ((Number) stat.get("count")).intValue()).sum());
        result.put("total_read", statistics.stream().mapToInt(stat -> ((Number) stat.get("read_count")).intValue()).sum());
        result.put("total_unread", statistics.stream().mapToInt(stat -> ((Number) stat.get("unread_count")).intValue()).sum());
        
        return result;
    }

    @Override
    public List<Map<String, Object>> getUserNotificationPreferences(Long userId) {
        return notificationMapper.getUserNotificationPreferences(userId);
    }

    @Override
    @Transactional
    public Integer cleanupExpiredNotifications() {
        try {
            Integer count = notificationMapper.deleteExpiredNotifications(LocalDateTime.now());
            log.info("清理过期通知，数量: {}", count);
            return count;
        } catch (Exception e) {
            log.error("清理过期通知失败", e);
            return 0;
        }
    }

    @Override
    public Notification createScheduledReminder(Long userId, String title, String content, LocalDateTime scheduledAt, String repeatType) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("REMINDER")
                .setTitle(title)
                .setContent(content)
                .setPriority("NORMAL")
                .setChannel("WEB")
                .setScheduledAt(scheduledAt);
        
        // 设置重复类型到数据字段
        if (repeatType != null) {
            notification.setData("{\"repeatType\":\"" + repeatType + "\"}");
        }
        
        return createNotification(notification);
    }

    @Override
    @Transactional
    public Boolean cancelScheduledReminder(Long userId, Long notificationId) {
        return deleteNotification(userId, notificationId);
    }

    @Override
    public Boolean updateNotificationSettings(Long userId, Map<String, Object> settings) {
        // 这里可以实现用户通知设置的更新逻辑
        // 暂时返回true，实际项目中需要实现用户设置表
        log.info("更新用户通知设置，用户: {}, 设置: {}", userId, settings);
        return true;
    }

    @Override
    public Map<String, Object> getNotificationSettings(Long userId) {
        // 这里可以实现获取用户通知设置的逻辑
        // 暂时返回默认设置，实际项目中需要从用户设置表获取
        Map<String, Object> settings = new HashMap<>();
        settings.put("web_notifications", true);
        settings.put("email_notifications", true);
        settings.put("sms_notifications", false);
        settings.put("push_notifications", true);
        return settings;
    }

    @Override
    public Boolean pushRealTimeNotification(Long userId, Notification notification) {
        // 这里可以实现WebSocket推送逻辑
        log.info("推送实时通知，用户: {}, 通知: {}", userId, notification.getTitle());
        return true;
    }

    @Override
    public Notification createEmergencyNotification(Long userId, String title, String content, String actionUrl) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType("EMERGENCY")
                .setTitle(title)
                .setContent(content)
                .setPriority("URGENT")
                .setChannel("WEB")
                .setActionUrl(actionUrl);
        return createNotification(notification);
    }

    @Override
    @Transactional
    public Integer broadcastSystemNotification(String title, String content, List<Long> targetUserIds) {
        try {
            List<Notification> notifications = new ArrayList<>();
            
            if (targetUserIds == null || targetUserIds.isEmpty()) {
                // 如果没有指定用户，这里可以获取所有用户ID
                // 暂时跳过，实际项目中需要从用户表获取所有用户ID
                log.warn("广播通知未指定目标用户");
                return 0;
            }
            
            for (Long userId : targetUserIds) {
                Notification notification = new Notification()
                        .setUserId(userId)
                        .setType("SYSTEM")
                        .setTitle(title)
                        .setContent(content)
                        .setPriority("HIGH")
                        .setChannel("WEB");
                notifications.add(notification);
            }
            
            return batchCreateNotifications(notifications);
        } catch (Exception e) {
            log.error("广播系统通知失败", e);
            return 0;
        }
    }

    /**
     * 模拟发送通知
     * @param notification 通知对象
     * @return 是否成功
     */
    private boolean simulateSendNotification(Notification notification) {
        // 模拟发送逻辑，实际项目中需要根据channel类型调用不同的发送服务
        try {
            Thread.sleep(100); // 模拟网络延迟
            return Math.random() > 0.1; // 90%成功率
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
}